package session

import (
	"time"
	"math/rand"
	"encoding/base64"
)

var manager *sessions

const (
	defaultValueNumber  = 32
	defaultExpireTime   = time.Hour
	defaultSessionName  = "GO_SESSION"
	defaultCookieDomain = ""
	defaultCookiePath   = "/"
)

type Option struct {
	Name 	string
	Path   	string
	Domain 	string
	Secure 	bool
	Expire 	time.Duration

	Store   	Store
	Provider   	Provider
}

type sessions struct {
	SessionName	string
	Store		Store
	Provider    Provider
	Expire      time.Duration
}

func Initialize(option ...Option) error {
	o := initOption(option...)

	manager = &sessions{
		SessionName: o.Name,
		Store: 		 o.Store,
		Provider: 	 o.Provider,
		Expire:      o.Expire,
	}

	manager.Store.SetExpire(manager.Expire)

	if err := manager.start(); err != nil {
		return err
	}

	return nil
}

func Manager() *sessions {
	if manager == nil {
		Initialize()
	}
	return manager
}

func (sessions *sessions) exist(id string) bool {
	return sessions.Store.Exist(id)
}

func (sessions *sessions) start() error {
	return sessions.Store.Start()
}

func initOption(options ...Option) Option {
	var o Option

	if len(options) > 0 {
		o = options[0]
	}

	if len(o.Name) <= 0 {
		o.Name = defaultSessionName
	}

	if len(o.Domain) <= 0 {
		o.Domain = defaultCookieDomain
	}

	if len(o.Path) <= 0 {
		o.Path = defaultCookiePath
	}

	if o.Expire <= 0 {
		o.Expire = defaultExpireTime
	}

	if o.Store == nil {
		o.Store = NewStoreMemory()
	}

	if o.Provider == nil {
		o.Provider = NewCookie(o.Name, o.Domain, o.Path, o.Secure, o.Expire)
	}

	return o
}

func createSessionID() (string, error) {
	b := make([]byte, defaultValueNumber)
	if _, err := rand.Read(b); err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(b), nil
}

func validateSessionID(sessionId string) bool {
	b, err := base64.StdEncoding.DecodeString(sessionId)
	if err != nil {
		return false
	}
	return len(b) == defaultValueNumber
}